﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.IO;
using System.Xml;

namespace StandaloneSilverlightWoZ.Web
{
    public partial class Reports : System.Web.UI.Page
    {
        const string _settingsFileName = "ActiveStorySettings.slsx";
        const string COLLECTEDDATAFILEEXTENSION = ".sldx";
        DataTable dtTestInstanceList;
        DataTable dtUserDetails;
        static string currentUserGuid = String.Empty;
        protected void Page_Load(object sender, EventArgs e)
        {
            LoadTestInstanceList();
        }

        void LoadTestInstanceList()
        {
            dtTestInstanceList = new DataTable("TestResultsByUser");
            dtTestInstanceList.Columns.Add("UserGUID", typeof(string));
            dtTestInstanceList.Columns.Add("DateTime", typeof(DateTime));
            string appDataDir = GetAbsoluteAppDataPath(String.Empty); //Gets the application data directory
            string[] filenames = Directory.GetFiles(appDataDir, "*" + COLLECTEDDATAFILEEXTENSION, SearchOption.TopDirectoryOnly);
            if (filenames.Length == 0)
            {
                Label noReports = new Label();
                noReports.Text="No reports are available";
                noReports.ForeColor = System.Drawing.Color.White;
                noReports.Font.Bold = true;
                noReports.Style[HtmlTextWriterStyle.TextAlign] = "center";
                Page.Controls.Add(noReports);
                return;
            }
            foreach (String item in filenames)
            {
                dtTestInstanceList.Rows.Add(Path.GetFileNameWithoutExtension(item), File.GetCreationTimeUtc(item).ToLocalTime());
            }
            dtTestInstanceList.DefaultView.Sort = "DateTime ASC";
            TestRunList.DataSource = dtTestInstanceList;
            TestRunList.DataBind();
        }

        public static string GetAbsoluteAppDataPath(string filename)
        {
            string physPath = HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath);
            String uri = Path.Combine(physPath, @"App_Data\") + filename;
            return uri;
        }

        public static string GetAbsoluteDataPath(string filename)
        {
            string physPath = HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath);
            String uri = Path.Combine(physPath, @"WoZData\") + filename;
            return uri;
        }


        protected void TestRunList_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadUserDetails(TestRunList.SelectedRow.Cells[0].Text);
            currentUserGuid = (String)TestRunList.SelectedRow.Cells[0].Text.Clone();
            UserPageDetails.SelectedIndex = -1;
            MouseTrailsLabel.Visible = false;
            MouseTrailsImage.Visible = false;
        }

        void LoadUserDetails(string userGUID)
        {
            dtUserDetails = new DataTable();
            dtUserDetails.Columns.Add("Sequence", typeof(int));
            dtUserDetails.Columns.Add("PageNumber", typeof(int));
            dtUserDetails.Columns.Add("PageDuration", typeof(TimeSpan));
            dtUserDetails.Columns.Add("SourceButton", typeof(String));
            dtUserDetails.Columns.Add("Comments", typeof(String));

            ParseUserResultFile(userGUID, dtUserDetails);
            
            UserPageDetails.DataSource = dtUserDetails;
            UserPageDetails.DataBind();
            UserPageDetails.Visible = true;
        }

        private void ParseUserResultFile(string userGUID, DataTable dtUserDetails)
        {
            FileStream fs=new FileStream(GetAbsoluteAppDataPath(userGUID + COLLECTEDDATAFILEEXTENSION), FileMode.Open);
            XmlReaderSettings xrs = new XmlReaderSettings();
            xrs.CloseInput= true;
            XmlReader xr = XmlReader.Create(fs, xrs);
            xr.ReadStartElement(SilverlightCollectedDataXmlElements.RootElement);

            xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageCountElement);
            int pageCount =xr.ReadContentAsInt();
            xr.ReadEndElement();

            for (int i=0;i<pageCount;i++)
            {
                xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageItemElement);

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageNumberElement);
                int pageNumber= xr.ReadContentAsInt();
                xr.ReadEndElement();

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.DurationElement);
                TimeSpan pageDuration = TimeSpan.Parse(xr.ReadContentAsString());
                xr.ReadEndElement();

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.CommentsElement);
                String comments = Server.HtmlDecode(xr.ReadContentAsString());
                xr.ReadEndElement();

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.SourceButtonNumElement);
                string sourceButton = xr.ReadContentAsString();
                xr.ReadEndElement();
                if (sourceButton.Equals("-10"))       //No button clicked due to being last page
                    sourceButton = "None";

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointListElement);

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointCount);
                int mousePointCount = xr.ReadContentAsInt();
                xr.ReadEndElement();

                for (int j=0;j<mousePointCount;j++)
                {
                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointElement);

                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointXElement);
                    xr.Read();
                    xr.ReadEndElement();

                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointYElement);
                    xr.Read();
                    xr.ReadEndElement();

                    xr.ReadEndElement();
                }
                xr.ReadEndElement();   //End Moue Point List Element

                xr.ReadEndElement();   //End Page Item Element

                dtUserDetails.Rows.Add(i, pageNumber, pageDuration, sourceButton, comments);
            }

            xr.ReadEndElement();   //End Root Element
            xr.Close();
        }

        protected void UserPageDetails_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadMouseTrailImage(int.Parse(UserPageDetails.SelectedRow.Cells[1].Text), currentUserGuid, int.Parse(UserPageDetails.SelectedRow.Cells[0].Text));
            MouseTrailsImage.Visible = true;
            MouseTrailsLabel.Visible = true;
        }

        void LoadMouseTrailImage(int pageNumber, string userGUID, int sequenceNumber)
        {
            string pageFileName = GetPageFileName(pageNumber);
            if (pageFileName.Equals(String.Empty))
                return;
            string pageImageFile = GetPageImageFile(pageFileName);
            System.Drawing.Image pageImage = System.Drawing.Bitmap.FromFile(GetAbsoluteDataPath(pageImageFile));
            LoadMouseTrails(System.Drawing.Graphics.FromImage(pageImage), userGUID, pageNumber, sequenceNumber);
            if (File.Exists(GetAbsoluteDataPath(@"TrailImages\" + userGUID + "-" + sequenceNumber + ".png")))
                File.Delete(GetAbsoluteDataPath(@"TrailImages\" + userGUID + "-" + sequenceNumber + ".png"));
            pageImage.Save(GetAbsoluteDataPath(@"TrailImages\" + userGUID + "-" + sequenceNumber + ".png"), System.Drawing.Imaging.ImageFormat.Png);
            MouseTrailsImage.ImageUrl = "/WoZData/TrailImages/" + userGUID + "-" + sequenceNumber + ".png";
        }

        private string GetPageImageFile(string pageFileName)
        {
            XmlReaderSettings xws = new XmlReaderSettings();
            xws.CloseInput = true;
            XmlReader xr = XmlReader.Create(GetAbsoluteDataPath(pageFileName), xws);
            xr.ReadStartElement(PageSilverlightXmlNames.RootElement);

            xr.ReadStartElement(PageSilverlightXmlNames.PageNumberElement);
            xr.Read();
            xr.ReadEndElement();

            xr.ReadStartElement(PageSilverlightXmlNames.PageImageElement);
            String imageFileLocation = xr.ReadContentAsString();
            xr.Close();
            return imageFileLocation;
        }


        private string GetPageFileName(int pageNumber)
        {
            //Find Project File location by reading settings file
            string filename = _settingsFileName;
            XmlReaderSettings xws = new XmlReaderSettings();
            xws.CloseInput = true;
            XmlReader xr = XmlReader.Create(GetAbsoluteDataPath(filename), xws);
            xr.ReadStartElement(SilverlightSettingsXmlNames.RootElement);

            xr.ReadStartElement(SilverlightSettingsXmlNames.ProjectFileLocationElement);
            string projectFileLocation = xr.ReadContentAsString();
            xr.ReadEndElement();
            xr.Close();

            xr = XmlReader.Create(GetAbsoluteDataPath(projectFileLocation), xws);
            xr.ReadStartElement(ProjectSilverlightXmlNames.RootElement);

            xr.ReadStartElement(ProjectSilverlightXmlNames.ProjectNameElement);
            xr.Read();
            xr.ReadEndElement();

            xr.ReadStartElement(ProjectSilverlightXmlNames.StartupPageElement);
            xr.Read();
            xr.ReadEndElement();

            xr.ReadStartElement(ProjectSilverlightXmlNames.PageCollectionElement);

            xr.ReadStartElement(ProjectSilverlightXmlNames.PageCountElement);
            int pageCount = xr.ReadContentAsInt();
            xr.ReadEndElement();

            string pageFileLocation=String.Empty;
            for (int i = 0; i < pageCount; i++)
            {
                xr.ReadStartElement(ProjectSilverlightXmlNames.PageFileElement);

                xr.ReadStartElement(ProjectSilverlightXmlNames.PageNumberElement);
                int itemPageNumber = xr.ReadContentAsInt();
                xr.ReadEndElement();

                xr.ReadStartElement(ProjectSilverlightXmlNames.PageFileLocationElement);
                pageFileLocation = xr.ReadContentAsString();
                xr.ReadEndElement();
                if (itemPageNumber == pageNumber)
                {
                    xr.Close();
                    return pageFileLocation;
                }
                xr.ReadEndElement();
            }
            xr.Close();
            return String.Empty;
        }

        private void LoadMouseTrails(System.Drawing.Graphics graphics, string userGUID, int pageNumber, int sequenceNumber)
        {
            FileStream fs = new FileStream(GetAbsoluteAppDataPath(userGUID + COLLECTEDDATAFILEEXTENSION), FileMode.Open);
            XmlReaderSettings xrs = new XmlReaderSettings();
            xrs.CloseInput = true;
            XmlReader xr = XmlReader.Create(fs, xrs);
            xr.ReadStartElement(SilverlightCollectedDataXmlElements.RootElement);

            xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageCountElement);
            int pageCount = xr.ReadContentAsInt();
            xr.ReadEndElement();

            for (int i = 0; i < pageCount; i++)
            {
                if (i != sequenceNumber)
                {
                    xr.Read();
                    xr.Skip();
                    continue;
                }
                xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageItemElement);

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.PageNumberElement);
                xr.Read();
                xr.ReadEndElement();

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.DurationElement);
                xr.Read();
                xr.ReadEndElement();

                //xr.Read();      //Wierdly it stops before Comments on this particular call, works everywhere else for the same file..
                xr.ReadStartElement(SilverlightCollectedDataXmlElements.CommentsElement);
                if (xr.NodeType == XmlNodeType.EndElement)
                {
                    xr.ReadEndElement();
                }
                else
                {
                    xr.Read();
                    xr.ReadEndElement();
                }

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.SourceButtonNumElement);
                xr.Read();
                xr.ReadEndElement();

                List<System.Drawing.Point> mousePointList = new List<System.Drawing.Point>();
                
                xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointListElement);

                xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointCount);
                int mousePointCount = xr.ReadContentAsInt();
                xr.ReadEndElement();

                for (int j = 0; j < mousePointCount; j++)
                {
                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointElement);

                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointXElement);
                    double x = xr.ReadContentAsDouble();
                    xr.ReadEndElement();

                    xr.ReadStartElement(SilverlightCollectedDataXmlElements.MousePointYElement);
                    double y = xr.ReadContentAsDouble();
                    xr.ReadEndElement();

                    xr.ReadEndElement();
                    mousePointList.Add(new System.Drawing.Point((int)x, (int)y));
                }
                xr.Close();
                DrawTrails(graphics, mousePointList);
                return;
            }

            xr.ReadEndElement();   //End Root Element
            xr.Close();
        }

        private void DrawTrails(System.Drawing.Graphics graphics, List<System.Drawing.Point> mousePointList)
        {
            if (mousePointList.Count == 0)
                return;
            graphics.DrawLines(new System.Drawing.Pen(System.Drawing.Color.Blue), mousePointList.ToArray<System.Drawing.Point>());
        }

        public static class SilverlightCollectedDataXmlElements
        {
            public const string RootElement = "CollectedData";
            public const string PageCountElement = "PageCount";
            public const string PageItemElement = "PageInstance";
            public const string PageNumberElement = "PageNumber";
            public const string DurationElement = "Duration";
            public const string CommentsElement = "Comments";
            public const string SourceButtonNumElement = "SourceButtonNumber";
            public const string MousePointListElement = "MousePointList";
            public const string MousePointCount = "MousePointCount";
            public const string MousePointElement = "MousePoint";
            public const string MousePointXElement = "X";
            public const string MousePointYElement = "Y";
        }
        public static class SilverlightSettingsXmlNames
        {
            public const string RootElement = "SilverlightSettings";
            public const string ProjectFileLocationElement = "ProjectFileLocation";
            public const string TaskInstructionsElement = "TaskInstructions";
        }
        public static class ProjectSilverlightXmlNames
        {
            public const string RootElement = "Project";
            public const string ProjectNameElement = "ProjectName";
            public const string StartupPageElement = "StartupPage";
            public const string PageCollectionElement = "PageCollection";
            public const string PageCountElement = "PageCount";
            public const string PageFileElement = "PageFile";
            public const string PageNumberElement = "PageNumber";
            public const string PageFileLocationElement = "PageLocation";
        }
        public static class PageSilverlightXmlNames
        {
            public const string RootElement = "Page";
            public const string PageNumberElement = "PageNumber";
            public const string PageImageElement = "PageImage";
        }
    }
}
